package tcp

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"os"
)

var (
	logFileName = flag.String("log", "tcp.log", "log file name")
)

func init() {
	//logFile, _ := os.OpenFile(*logFileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
	//log.SetOutput(logFile)
	log.SetOutput(os.Stdout)
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

//这个方法是每次开个新的线程来处理请求，传统方式，性能不一定高，对于go来说
//goroutine是轻量级的线程，所以可能还好点。
func startTcpServer(handle func(conn net.Conn), ip string, port int) {
	ipPort := fmt.Sprintf("%s:%d", ip, port)
	log.Printf("start tcp server ip:port %v \n", ipPort)
	listen, err := net.Listen("tcp", ipPort)
	if err != nil {
		fmt.Println("listen failed, err:", err)
		return
	}
	log.Printf("start tcp server success")
	for {
		conn, err := listen.Accept() // 建立连接
		if err != nil {
			fmt.Println("accept failed, err:", err)
			continue
		}
		//log.Printf("client connected ....")
		go handle(conn) // 启动一个goroutine处理连接
	}
}

//StartTcpServerWithLen 固定长度的解析TCP包
// 这个版本是阻塞版本，没有用到多线程，更没有用到epoll
func StartTcpServerWithLen(handle func([]byte), ip string, port int) {
	ipPort := fmt.Sprintf("%s:%d", ip, port)
	log.Printf("start tcp server ip:port %v \n", ipPort)
	listen, err := net.Listen("tcp", ipPort)
	if err != nil {
		fmt.Println("listen failed, err:", err)
		return
	}
	defer listen.Close()
	log.Printf("start tcp server success")
	for {
		conn, err := listen.Accept() // 建立连接
		if err != nil {
			fmt.Println("accept failed, err:", err)
			continue
		}
		defer conn.Close()
		reader := bufio.NewReader(conn)
		for {
			//先读取4个字节，表示长度 Peek表示只读取，而不从流里实际拿出来。
			//有错误也正常，表示没拿到4个长度
			peek, err := reader.Peek(HEAD_LEN)

			if err != nil {
				// EOF就表示终止了，没必要继续读了
				if err == io.EOF {
					break
				} else {
					log.Println("tcp server read head error：", err)
				}
			}
			//这里需要把4个字节的数组，转换为实际的长度
			buffer := bytes.NewBuffer(peek)
			var length int32
			//读到4个字节的长度了，存到length
			err = binary.Read(buffer, binary.BigEndian, &length)
			if err != nil {
				if err == io.EOF {
					log.Println("tcp server read head error：", err)
					break
				}
				log.Println("tcp server read head len error：", err)
			}
			if int32(reader.Buffered()) < length+HEAD_LEN_INT32 {
				log.Println("tcp server length:", length, " buffered: ", int32(reader.Buffered()))
				continue
			}
			data := make([]byte, length+HEAD_LEN_INT32)
			_, err = reader.Read(data)
			if err != nil {
				continue
			}
			//获取到TCP的数据了，交给用户自定义的函数处理数据。
			handle(data[HEAD_LEN_INT32:])
		}
	}
}

func closeConn(c net.Conn) {

	log.Println("client close: local: ", c.LocalAddr(), " remote:", c.RemoteAddr())
	c.Close()
}

func startTcpServerWithSelect(handle func(conn net.Conn), ip string, port int) {
	ipPort := fmt.Sprintf("%s:%d", ip, port)
	log.Printf("start tcp server ip:port %v \n", ipPort)
	listen, err := net.Listen("tcp", ipPort)
	if err != nil {
		fmt.Println("listen failed, err:", err)
		return
	}
	log.Printf("start tcp server success")

	// 这里用select来处理
	conns := make(chan net.Conn, 100)
	done := make(chan struct{})

	go func() {
		for {
			select {
			case <-done:
			//do
			case conn, _ := <-conns:
				//
				handle(conn)
			}
		}
	}()

	for {
		conn, err := listen.Accept() // 建立连接
		if err != nil {
			fmt.Println("accept failed, err:", err)
			continue
		}
		log.Printf("client connected ....")
		conns <- conn
	}

}
